package com.ht.module.base.service.impl;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ht.abnormal.HtException;
import com.ht.config.task.ScheduledOfTask;
import com.ht.constant.BusConstant;
import com.ht.constant.DicConstants;
import com.ht.constant.RedisConstants;
import com.ht.module.base.entity.BaseScheduledTask;
import com.ht.module.base.mapper.BaseScheduledTaskMapper;
import com.ht.module.base.service.IBaseScheduledTaskService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ht.util.CommMethod;
import com.ht.util.Pager;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;

import static java.lang.Thread.sleep;

/**
 * <p>
 * 定时任务表 服务实现类
 * </p>
 *
 * @author hejialun
 * @since 2022-04-24
 */
@Service
public class BaseScheduledTaskServiceImpl extends ServiceImpl<BaseScheduledTaskMapper, BaseScheduledTask> implements IBaseScheduledTaskService {
    @Resource
    private RedissonClient redissonClient;
    /**
     * 定时任务线程池
     */
    @Autowired
    private ThreadPoolTaskScheduler threadPoolTaskScheduler;

    /**
     * 启动状态的定时任务集合
     */
    public Map<String, ScheduledFuture> scheduledFutureMap = new ConcurrentHashMap<String, ScheduledFuture>();


    @Override
    public Pager<BaseScheduledTask> findPage(Pager<BaseScheduledTask> pager, BaseScheduledTask en) {
        QueryWrapper<BaseScheduledTask> qw = new QueryWrapper<>();
        if (StrUtil.isNotEmpty(en.getTaskName())) {
            qw.like("task_name", en.getTaskName());
        }
        if (StrUtil.isNotEmpty(en.getBackTask())) {
            qw.eq("back_task", en.getBackTask());
        }
        return baseMapper.selectPage(pager, qw);
    }

    @Override
    public List<BaseScheduledTask> listAll() {
        return this.list();
    }

    @Override
    public BaseScheduledTask getById(String id) {
        return baseMapper.selectById(id);
    }

    @Override
    public BaseScheduledTask findByTaskClass(String taskClass) {
        QueryWrapper<BaseScheduledTask> qw = new QueryWrapper<BaseScheduledTask>();
        qw.eq("back_task", taskClass);
        return this.getOne(qw);
    }

    @Override
    public void start(String id) {
        //锁住当前任务
        RLock lock = redissonClient.getLock(RedisConstants.TASK_LOCK_PREFIX+id);
        //获取锁资源
        if (lock.isLocked()) {
            throw new HtException(BusConstant.LOOK_MESSAGE);
        }
        //加锁
        lock.lock();
        //判断是否存在已经激活的任务
        boolean flag = scheduledFutureMap.containsKey(id);
        if (!flag) {
            BaseScheduledTask task = this.getById(id);
            //激活
            this.doStartTask(task);
        } else{
            log.error("定时任务已经激活，不可重复激活!");
        }
        //释放锁
        lock.unlock();
    }

    @Override
    public void stop(String id) {
        //锁住当前任务
        RLock lock = redissonClient.getLock(RedisConstants.TASK_LOCK_PREFIX+id);
        //获取锁资源
        if (lock.isLocked()) {
            throw new HtException(BusConstant.LOOK_MESSAGE);
        }
        lock.lock();
        // 根据id查询任务
        boolean flag = scheduledFutureMap.containsKey(id);
        if (flag) {
            ScheduledFuture scheduledFuture = scheduledFutureMap.get(id);
            scheduledFuture.cancel(true);
            scheduledFutureMap.remove(id);
        } else {
            log.error("当前任务未激活!");
        }
        lock.unlock();
    }

    @Override
    public void restart(String id) {
        // 停止
        this.stop(id);
        // 启动
        this.start(id);

    }

    @Override
    public void initTask() {
        List<BaseScheduledTask> stList = this.list();
        if (null != stList && !stList.isEmpty()) {
            // 循环所有定时任务
            for (BaseScheduledTask st : stList) {
                // 判断是否启用
                if (st.getState().equals(DicConstants.TaskState.STOP)) {
                    continue;
                }
                // 执行任务
                doStartTask(st);
            }
        }
    }

    @Override
    public void delById(String id) {
        //锁住当前任务
        RLock lock = redissonClient.getLock(RedisConstants.TASK_LOCK_PREFIX+id);
        //获取锁资源
        if (lock.isLocked()) {
            throw new HtException(BusConstant.LOOK_MESSAGE);
        }
        //加锁
        lock.lock();
        //停止当前任务呀
        //判断是否存在激活状态的任务
        boolean flag = scheduledFutureMap.containsKey(id);
        if (flag) {
            this.stop(id);
        }
        //删除任务
        baseMapper.deleteById(id);
        lock.unlock();
    }

    @Override
    public void add(BaseScheduledTask en) {
        //判断是否存在已经定义了的后台任务
        if(baseMapper.selectCount(
                new QueryWrapper<BaseScheduledTask>()
                        .eq("back_task",en.getBackTask())
        )>0){
            throw new HtException("当前任务已经存在不可重复创建!");
        }
        CommMethod.beanCreate(en);
        baseMapper.insert(en);
    }

    @Override
    public void editById(BaseScheduledTask en) {
        //锁住当前任务
        RLock lock = redissonClient.getLock(RedisConstants.TASK_LOCK_PREFIX+en.getId());
        //获取锁资源
        if (lock.isLocked()) {
            throw new HtException(BusConstant.LOOK_MESSAGE);
        }
        //加锁
        lock.lock();
        //判断是否存在已经定义了的后台任务
        if(baseMapper.selectCount(
                new QueryWrapper<BaseScheduledTask>()
                        .eq("back_task",en.getBackTask())
                        .ne("id",en.getId())
        )>0){
            throw new HtException("当前任务已经存在不可重复创建!");
        }
        CommMethod.beanUpdate(en);
        baseMapper.updateById(en);
        lock.unlock();
    }


    /**
     * @param scheduledTask:任务实体
     * @return void
     * @Author hejialun
     * @Date 16:24 2022/4/25
     * @Description TODO(执行启动任务)
     */
    private void doStartTask(BaseScheduledTask scheduledTask) {
        Class clazz;
        ScheduledOfTask task;
        try {
            clazz = Class.forName(scheduledTask.getBackTask());
            task = (ScheduledOfTask) SpringUtil.getBean(clazz);
            Assert.isAssignable(ScheduledOfTask.class, task.getClass(), "定时任务类必须实现ScheduledOfTask接口");
            ScheduledFuture scheduledFuture = threadPoolTaskScheduler.schedule(task, (triggerContext -> new CronTrigger(scheduledTask.getCorn()).nextExecutionTime(triggerContext)));
            scheduledFutureMap.put(scheduledTask.getId(), scheduledFuture);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }


    /**
     * @param id
     * @return java.lang.Boolean
     * @Author hejialun
     * @Date 17:21 2022/4/25
     * @Description TODO(检查任务是否已经启动)
     */
    private Boolean isStart(String id) {
        // 校验是否已经启动
        if (scheduledFutureMap.containsKey(id)) {
            if (!scheduledFutureMap.get(id).isCancelled()) {
                return true;
            }
        }
        return false;
    }

}
